local skynet = require "skynet"
local filename = "slotmgr.lua"
local filelog = require "filelog"
local queue = require "skynet.queue"
local base = require "base"
local redisdao = require "redisdao"
local tabletool = require "tabletool"
local json = require "cjson"
json.encode_sparse_array(true,1,1)

local SlotTool = require "slottool"
require "diceenum"

------------
--枚举类
local dices_two_normal = {
    [2]  = {{1,1},},
    [3]  = {{1,2},{2,1},},
    [4]  = {{1,3},{3,1},{2,2},},
    [5]  = {{1,4},{4,1},{2,3},{3,2},},
    [6]  = {{1,5},{5,1},{2,4},{4,2},{3,3},},
    [7]  = {{1,6},{6,1},{2,5},{5,2},{3,4},{4,3},},
    [8]  = {{2,6},{6,2},{3,5},{5,3},{4,4},},
    [9]  = {{3,6},{6,3},{4,5},{5,4},},
    [10] = {{4,6},{6,4},{5,5},},
    [11] = {{5,6},{6,5},},
    [12] = {{6,6},},
}

--系统输钱上限基值,默认10万
local SystemLoseLimit_Base = 1000000

--系统输钱上限控制系数
local SystemLoseLimit_Factor = 0.08

--开奖类型
local LotteryType = {
    LOTTERY_TYPE_SYSTEM_WIN = 1,   --系统必赢
    LOTTERY_TYPE_SYSTEM_LOSE = 2,  --系统必输
    LOTTERY_TYPE_NORMAL = 3,       --正常开奖
}
----------------------
--倍率列表
local Odds_list = {
    [1101] =  2,
    [1102] =  5,
    [1103] =  2,

    --------
    [2101] =  28,
    [2102] =  15,
    [2103] =  10,
    [2104] =   8,
    [2105] =   6,
    [2106] =   6,
    [2107] =   8,
    [2108] =  10,
    [2109] =  15,
    [2110] =  28,
}

local Weight_list = {
    [2] = 278,
    [3] = 556,
    [4] = 833,
    [5] = 1111,
    [6] = 1389,
    [7] = 1667,
    [8] = 1389,
    [9] = 1111,
    [10] = 833,
    [11] = 556,
    [12] = 278,
}

--权值项对应倍率列表
local Witem_odds_list = {
    [2] = {1101, 2101},
    [3] = {1101, 2102},
    [4] = {1101, 2103},
    [5] = {1101, 2104},
    [6] = {1101, 2105},
    [7] = {1102},
    [8] = {1103, 2106},
    [9] = {1103, 2107},
    [10] = {1103, 2108},
    [11] = {1103, 2109},
    [12] = {1103, 2110},
}
--系统库存概率表
--S = 库存值
local S_list = {
    [1] = { -- S < -500万
        nohit = 1.00,   --必不中概率
        normal = 0.00,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [2] = { -- -500万<=S<-100万
        nohit = 0.80,   --必不中概率
        normal = 0.20,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [3] = { -- -100万<=S<-20万
        nohit = 0.60,   --必不中概率
        normal = 0.40,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [4] = { -- -20万<=S<-10万
        nohit = 0.30,   --必不中概率
        normal = 0.70,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [5] = { -- -10万<=S<200万
        nohit = 0.00,   --必不中概率
        normal = 1.00,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [6] = { -- 200万<=S<1000万
        nohit = 0.00,   --必不中概率
        normal = 0.80,  --正常开奖概率
        hit = 0.20,     --必中概率
    },
    [7] = { -- 1000万<=S<5000万
        nohit = 0.00,   --必不中概率
        normal = 0.60,  --正常开奖概率
        hit = 0.40,     --必中概率
    },
    [8] = { -- 5000万<=S<1亿
        nohit = 0.00,   --必不中概率
        normal = 0.50,  --正常开奖概率
        hit = 0.50,     --必中概率
    },
    [9] = { -- S>=1亿
        nohit = 0.00,   --必不中概率
        normal = 0.40,  --正常开奖概率
        hit = 0.60,     --必中概率
    },
}
--------------------------
--辅助表
--图标概率表，由权重表生成
local Prob_list = nil
--图标总权值,，由权重表生成
local Total_weight = nil
--预存牌型表,每种5种
local Profile_Cards_List = {           
}

local function get_dicespoint(sum_id)
    local dices_pool = dices_two_normal[sum_id]
    if not dices_pool  then
        return {}
    else
        local get_index = base.get_random(1, #dices_pool)
        local get_dices = dices_pool[get_index]
        if not get_dices then
            return {}
        else
            return get_dices
        end
    end
end

local function get_sum_id_by_betid(bet_id)
    local sumid = 0
    for sum_id, betid in pairs(EDICEBtnIDSum) do
        if bet_id == betid then sumid = sum_id break end
    end
    return sumid
end

--更新图标概率表
function SlotTool.update_picture_prob_list()
    local prob_list = {}

    local total_prob = 0
    local total_weight = SlotTool.calculate_total_weight(Weight_list)
    for id,w in pairs(Weight_list) do
        prob_list[id] = w / total_weight
        total_prob = total_prob + prob_list[id]
    end
        
    --总概率应为1
    if math.floor(total_prob * 100) ~= 100 then
        filelog.sys_error("total probability not equal to 1!",total_prob)
    end

    return prob_list,total_weight
end

--
--获取开奖类型
--返回 LotteryType类型
--
function SlotTool.get_lottery_type(gamename)
    --获取库存值
    local inventory = SlotTool.get_static_inventory_from_redis(gamename)

    local item = nil
    local s = inventory
    local a = 10000
    if s < -500 * a then
        item = S_list[1]
    elseif s >= -500 * a and s < -100 * a then
        item = S_list[2]
    elseif s >= -100 * a and s < -20 * a  then
        item = S_list[3]
    elseif s >= -20 * a and s < -10 * a then
        item = S_list[4]
    elseif s >= -10 * a and s < 200 * a then
        item = S_list[5]
    elseif s >= 200 * a and s < 1000 * a then
        item = S_list[6]
    elseif s >= 1000 * a and s < 5000 * a then
        item = S_list[7]
    elseif s >= 5000 * a and s < 10000 * a then
        item = S_list[8]
    elseif s >= 10000 * a then
        item = S_list[9]
    end

     --根据概率获取随机开奖类型
    local r = base.get_random(1, 1000)
    local hit = math.floor(item.hit * 1000)
    local nohit = hit + math.floor(item.nohit * 1000)
    local normal = nohit + math.floor(item.normal * 1000) 
    if r <= hit then
        return LotteryType.LOTTERY_TYPE_SYSTEM_LOSE
    elseif r <= nohit then
        return LotteryType.LOTTERY_TYPE_SYSTEM_WIN
    elseif r <= normal then
        return LotteryType.LOTTERY_TYPE_NORMAL
    end
end

--
--获取系统输赢列表
--
function SlotTool.get_system_win_lose_list(total_bet_list, total_bet, is_robot_banker)
    local sys_win_list = {}
    local sys_lose_list = {}

    if is_robot_banker then
        for id,odds in pairs(Odds_list) do
            local bet_id = id
            if odds > 0 and total_bet_list[bet_id] then
                local rtm = odds * total_bet_list[bet_id]   --返钱数
                if rtm  < total_bet then
                    table.insert(sys_win_list,id)
                elseif rtm > total_bet then
                    table.insert(sys_lose_list,id)
                end
            end
        end
    else
        for id,odds in pairs(Odds_list) do
            local bet_id = id
            if odds > 0 and total_bet_list[bet_id] then
                local rtm = odds * total_bet_list[bet_id]   --返钱数
                if rtm  > total_bet then
                    table.insert(sys_win_list,id)
                elseif rtm < total_bet then
                    table.insert(sys_lose_list,id)
                end
            end
        end
    end
    return sys_win_list,sys_lose_list
end
--
--获得系统输钱上限
--
function SlotTool.get_system_lose_limit(gamename)
    local loselimit = 0
    local S = SlotTool.get_static_inventory_from_redis(gamename)
    if S < 0 then
        loselimit = SystemLoseLimit_Base
    else
        loselimit = math.floor(S * SystemLoseLimit_Factor) + SystemLoseLimit_Base
    end

    return loselimit
end

--
--获得返钱数
--
function SlotTool.get_rtm(id, total_bet_list)
    local bet_id = id
    local odds = Odds_list[id] or 0
    local rtm = odds * (total_bet_list[bet_id] or 0)

    return rtm
end

--
--检测亏损值是否超过输钱上限
--
function SlotTool.check_is_greater_loselimit(id, total_bet, total_bet_list, is_robot_banker, loselimit)
    local rtm = SlotTool.get_rtm(id,total_bet_list)
    local ksz = total_bet - rtm
    if (is_robot_banker and ksz < -loselimit)
    or (not is_robot_banker and ksz > loselimit) then
        return true
    end

    return false
end

--
--获取系统必输随机结果
--去除超上限项
--
function SlotTool.get_mustlose_random_result(sys_lose_list, total_bet_list, gamename, total_bet, is_robot_banker)
    local loselimit = SlotTool.get_system_lose_limit(gamename)

    if sys_lose_list and #sys_lose_list > 0 then
        local lose_w_list = {}
        local total_weight = 0
        for _,id in pairs(sys_lose_list) do
            local is_ok = SlotTool.check_is_greater_loselimit(id,total_bet,total_bet_list,is_robot_banker,loselimit)
            if not is_ok then
                local sumid = get_sum_id_by_betid(id)
                if sumid > 0 then
                    lose_w_list[id] = Weight_list[sumid]
                    total_weight = total_weight + lose_w_list[id]
                end
            end
        end
        ---filelog.sys_error("---------get_mustlose_random_result------", lose_w_list, total_weight, sys_lose_list)
        if next(lose_w_list) ~= nil then
            ---return SlotTool.get_random_result_by_weightlist(lose_w_list,total_weight)
            local id = SlotTool.get_random_result_by_weightlist(lose_w_list,total_weight)
            local sumid = get_sum_id_by_betid(id)
            local get_dices = get_dicespoint(sumid)
            local result_list = {
                all_cards = {},
                prize_ids = {},
                all_sum = 0,
            }
            if #get_dices ~= 2 then
                return result_list
            end
            local alldicesum = 0
            for index, dice in ipairs(get_dices) do
                table.insert(result_list.all_cards, dice)
                alldicesum = alldicesum + dice
            end
            if alldicesum >= EDICESumType.SUM_LITTLE[1] and alldicesum <= EDICESumType.SUM_LITTLE[2]  then
                table.insert(result_list.prize_ids, 1101)
            elseif alldicesum >= EDICESumType.SUM_EQUAL[1] and alldicesum <= EDICESumType.SUM_EQUAL[2]  then
                table.insert(result_list.prize_ids, 1102)
            elseif alldicesum >= EDICESumType.SUM_BIG[1] and alldicesum <= EDICESumType.SUM_BIG[2] then
                table.insert(result_list.prize_ids, 1103)
            end

            local bit_id = EDICEBtnIDSum[alldicesum]
            table.insert(result_list.prize_ids, bit_id)
            result_list.all_sum = alldicesum
            return result_list
        else
            return SlotTool.get_min_spin_result(total_bet_list,is_robot_banker)
        end
    end

    --当前押注使系统必定赢，则选择玩家赢钱最多的结果
    return SlotTool.get_max_spin_result(total_bet_list,is_robot_banker)
end

--
--获取系统必赢随机结果
--
function SlotTool.get_mustwin_random_result(sys_win_list, total_bet_list, is_robot_banker)
    if sys_win_list and #sys_win_list > 0 then
        local win_w_list = {}
        local total_weight = 0
        for _,id in pairs(sys_win_list) do
            local sumid = get_sum_id_by_betid(id)
            if sumid > 0 then
                win_w_list[id] = Weight_list[sumid]
                total_weight = total_weight + win_w_list[id]
            end
        end
        local id = SlotTool.get_random_result_by_weightlist(win_w_list,total_weight)
        local sumid = get_sum_id_by_betid(id)
        local get_dices = get_dicespoint(sumid)
        local result_list = {
            all_cards = {},
            prize_ids = {},
            all_sum = 0,
        }
        if #get_dices ~= 2 then
            return result_list
        end
        local alldicesum = 0
        for index, dice in ipairs(get_dices) do
            table.insert(result_list.all_cards, dice)
            alldicesum = alldicesum + dice
        end
        if alldicesum >= EDICESumType.SUM_LITTLE[1] and alldicesum <= EDICESumType.SUM_LITTLE[2]  then
            table.insert(result_list.prize_ids, 1101)
        elseif alldicesum >= EDICESumType.SUM_EQUAL[1] and alldicesum <= EDICESumType.SUM_EQUAL[2]  then
            table.insert(result_list.prize_ids, 1102)
        elseif alldicesum >= EDICESumType.SUM_BIG[1] and alldicesum <= EDICESumType.SUM_BIG[2] then
            table.insert(result_list.prize_ids, 1103)
        end

        local bit_id = EDICEBtnIDSum[alldicesum]
        table.insert(result_list.prize_ids, bit_id)
        result_list.all_sum = alldicesum
        return result_list
    end

    --当前押注使系统必输，则选择玩家赢钱最少的结果
    return SlotTool.get_min_spin_result(total_bet_list,is_robot_banker)
end

--
--获取普通随机结果
--去掉系统超上限亏损项
--
function SlotTool.get_normal_random_result(sys_lose_list, total_bet_list, gamename, total_bet, is_robot_banker)
    local loselimit = SlotTool.get_system_lose_limit(gamename)
    local random_id_list = tabletool.deepcopy(Weight_list)
    --去除超上限亏损
    if sys_lose_list and #sys_lose_list > 0 then
        for _,id in pairs(sys_lose_list) do
            local rtm = 0
            local bet_ids = Witem_odds_list[id] or {}
            for _,bet_id in pairs(bet_ids) do
                local odds = Odds_list[bet_id] or 2
                rtm = rtm + odds * (total_bet_list[bet_id] or 0)
            end
            local ksz =  total_bet - rtm
            if is_robot_banker and ksz < -loselimit then
                random_id_list[id] = nil
            elseif not is_robot_banker and ksz > loselimit then
                random_id_list[id] = nil
            end
        end
    end

    --所有项超上限，则返回最小的
    if next(random_id_list) == nil then
        return SlotTool.get_min_spin_result(total_bet_list,is_robot_banker)
    end
    --产生随机结果
    local all_cards = {}
    local sum_id = SlotTool.get_random_result_by_weightlist(random_id_list)
    local get_dices = get_dicespoint(sum_id)
    local result_list = {
        all_cards = {},
        prize_ids = {},
        all_sum = 0,
    }
    if #get_dices ~= 2 then
        return result_list
    end
    local alldicesum = 0
    for index, dice in ipairs(get_dices) do
        table.insert(result_list.all_cards, dice)
        alldicesum = alldicesum + dice
    end
    if alldicesum >= EDICESumType.SUM_LITTLE[1] and alldicesum <= EDICESumType.SUM_LITTLE[2]  then
        table.insert(result_list.prize_ids, 1101)
    elseif alldicesum >= EDICESumType.SUM_EQUAL[1] and alldicesum <= EDICESumType.SUM_EQUAL[2]  then
        table.insert(result_list.prize_ids, 1102)
    elseif alldicesum >= EDICESumType.SUM_BIG[1] and alldicesum <= EDICESumType.SUM_BIG[2] then
        table.insert(result_list.prize_ids, 1103)
    end

    local bit_id = EDICEBtnIDSum[alldicesum]
    table.insert(result_list.prize_ids, bit_id)
    result_list.all_sum = alldicesum
    return result_list
end

--
--获得纯随机结果
--
function SlotTool.get_real_random_result(all_rand_cards)
    local all_cards = {}
    local sum_id = SlotTool.get_random_result_by_weightlist(Weight_list)
    local get_dices = get_dicespoint(sum_id)
    --返回结果
    local result_list = {
        all_cards = {},
        prize_ids = {},
        all_sum = 0,
    }
    if #get_dices ~= 2 then
        return result_list
    end
    local alldicesum = 0
    for index, dice in ipairs(get_dices) do
        table.insert(result_list.all_cards, dice)
        alldicesum = alldicesum + dice
    end
    if alldicesum >= EDICESumType.SUM_LITTLE[1] and alldicesum <= EDICESumType.SUM_LITTLE[2]  then
        table.insert(result_list.prize_ids, 1101)
    elseif alldicesum >= EDICESumType.SUM_EQUAL[1] and alldicesum <= EDICESumType.SUM_EQUAL[2]  then
        table.insert(result_list.prize_ids, 1102)
    elseif alldicesum >= EDICESumType.SUM_BIG[1] and alldicesum <= EDICESumType.SUM_BIG[2] then
        table.insert(result_list.prize_ids, 1103)
    end

    local bit_id = EDICEBtnIDSum[alldicesum]
    table.insert(result_list.prize_ids, bit_id)
    result_list.all_sum = alldicesum
    return result_list
end

--
--获得可能的随机结果
--
function SlotTool.get_may_random_result(result_id)
    local all_cards = {}
    local real_all_cards = {}


    --返回结果
    local result_list = {
        all_cards = real_all_cards,
        prize_id = 0,
        ext_prize_list = prize_list,
        all_results = all_results,
    }

    return result_list
end

--
--产生一个随机旋转结果
--
function SlotTool.gen_random_dice_result(gamename, total_bet_list, total_bet, avg_bet, is_robot_banker, is_random, banker_round)
    local result_id = nil
    local result_list = nil
    --计算系统输赢列表
    local sys_win_list,sys_lose_list = SlotTool.get_system_win_lose_list(total_bet_list,total_bet,is_robot_banker)
    --随机开奖
    if is_random then
        return SlotTool.get_real_random_result()
    else
        local lottery_type = SlotTool.get_lottery_type(gamename)
        ---local lottery_type = LotteryType.LOTTERY_TYPE_SYSTEM_LOSE
        if lottery_type == LotteryType.LOTTERY_TYPE_SYSTEM_WIN then     --系统必赢
            return SlotTool.get_mustwin_random_result(sys_win_list,total_bet_list,is_robot_banker)
        elseif lottery_type == LotteryType.LOTTERY_TYPE_SYSTEM_LOSE then  --系统必输
            return SlotTool.get_mustlose_random_result(sys_lose_list,total_bet_list,gamename,total_bet,is_robot_banker)
        else    --随机开奖
            return SlotTool.get_normal_random_result(sys_lose_list,total_bet_list,gamename,total_bet,is_robot_banker)
        end
    end
    -- --根据开牌结果获取随机牌
    -- filelog.sys_error("--------------result_id-------------", result_id)
    -- local result_list = SlotTool.get_may_random_result(result_id)

    -- return result_list
end

--
--获取最小奖励
--
function SlotTool.get_min_spin_result(total_bet_list, is_robot_banker)
    local min_id = 0
    local min_rtm = 100000000000
    if not is_robot_banker then
        min_rtm = 0
    end
    
    --循环每一种情况,求返钱数最小的
    for id,_ in pairs(Weight_list) do
        local rtm = 0
        local bet_ids = Witem_odds_list[id] or {}
        for _,bet_id in pairs(bet_ids) do
            local odds =  Odds_list[bet_id] or 2
            if odds > 0 and total_bet_list[bet_id] then
                rtm = rtm + odds * (total_bet_list[bet_id] or 0)   --返钱数
            end
        end
        if is_robot_banker then
            if min_rtm > rtm then
                min_rtm = rtm
                min_id = id
            end
        else
            if min_rtm < rtm then
                min_rtm = rtm
                min_id = id
            end
        end
    end

    local sum_id = min_id
    local get_dices = get_dicespoint(sum_id)
    local result_list = {
        all_cards = {},
        prize_ids = {},
        all_sum = 0,
    }
    if #get_dices ~= 2 then
        return result_list
    end
    local alldicesum = 0
    for index, dice in ipairs(get_dices) do
        table.insert(result_list.all_cards, dice)
        alldicesum = alldicesum + dice
    end
    if alldicesum >= EDICESumType.SUM_LITTLE[1] and alldicesum <= EDICESumType.SUM_LITTLE[2]  then
        table.insert(result_list.prize_ids, 1101)
    elseif alldicesum >= EDICESumType.SUM_EQUAL[1] and alldicesum <= EDICESumType.SUM_EQUAL[2]  then
        table.insert(result_list.prize_ids, 1102)
    elseif alldicesum >= EDICESumType.SUM_BIG[1] and alldicesum <= EDICESumType.SUM_BIG[2] then
        table.insert(result_list.prize_ids, 1103)
    end

    local bit_id = EDICEBtnIDSum[alldicesum]
    table.insert(result_list.prize_ids, bit_id)
    result_list.all_sum = alldicesum
    return result_list
end

--
--获取最大奖励
--
function SlotTool.get_max_spin_result(total_bet_list, is_robot_banker)
    local max_id = 0
    local max_rtm = 0
    if not is_robot_banker then
        max_rtm = 100000000000
    end
    
    --循环每一种情况,求返钱数最大的
    for id,_ in pairs(Weight_list) do
        local rtm = 0
        local bet_ids = Witem_odds_list[id] or {}
        for _,bet_id in pairs(bet_ids) do
            local odds =  Odds_list[bet_id] or 2
            if odds > 0 and total_bet_list[bet_id] then
                rtm = rtm + odds * (total_bet_list[bet_id] or 0)   --返钱数
            end
        end
        if is_robot_banker then
            if max_rtm < rtm then
                max_rtm = rtm
                max_id = id
            end
        else
            if max_rtm > rtm then
                max_rtm = rtm
                max_id = id
            end
        end
    end
    local sum_id = max_id
    local get_dices = get_dicespoint(sum_id)
    local result_list = {
        all_cards = {},
        prize_ids = {},
        all_sum = 0,
    }
    if #get_dices ~= 2 then
        return result_list
    end
    local alldicesum = 0
    for index, dice in ipairs(get_dices) do
        table.insert(result_list.all_cards, dice)
        alldicesum = alldicesum + dice
    end
    if alldicesum >= EDICESumType.SUM_LITTLE[1] and alldicesum <= EDICESumType.SUM_LITTLE[2]  then
        table.insert(result_list.prize_ids, 1101)
    elseif alldicesum >= EDICESumType.SUM_EQUAL[1] and alldicesum <= EDICESumType.SUM_EQUAL[2]  then
        table.insert(result_list.prize_ids, 1102)
    elseif alldicesum >= EDICESumType.SUM_BIG[1] and alldicesum <= EDICESumType.SUM_BIG[2] then
        table.insert(result_list.prize_ids, 1103)
    end

    local bit_id = EDICEBtnIDSum[alldicesum]
    table.insert(result_list.prize_ids, bit_id)
    result_list.all_sum = alldicesum
    return result_list
end


--
--检测随机结果的正确性
--
function SlotTool.check_random_spin_result(spin_result)
    if not spin_result then
        return false
    end

    if #spin_result.all_cards ~= 2 then 
        return false
    elseif #spin_result.all_cards == 2 and #spin_result.prize_ids == 1 then
        if spin_result.all_sum ~= 7 then return false end
    end
    local is_ok = true

    for index, dice in pairs(spin_result.all_cards) do
        if dice < 1 or dice > 6 then
            is_ok = false
            break
        end
    end
    if is_ok == false then return is_ok end
    return is_ok
end

--
--处理送灯
--is_seq是否为连续灯
--
function SlotTool.handle_give_lamp(sd_w_list, is_seq)
    local result_list = {}

    --获得送灯数
    local lamp_num = SlotTool.get_random_result_by_weightlist(sd_w_list)
    if not lamp_num then
        return
    end

    --计算总权值
    local total_w = SlotTool.calculate_total_weight(SDFruit_weight_list)

    --随机获取lamp_num盏灯
    if is_seq then  --连续lamp_num盏灯
        local id = SlotTool.get_random_result_by_weightlist(SDFruit_weight_list,total_w)
        table.insert(result_list,id)
        table.insert(result_list,lamp_num)
    else
        for i = 1,lamp_num do
            local id = SlotTool.get_random_result_by_weightlist(SDFruit_weight_list,total_w)
            table.insert(result_list,id)
        end
    end
    
    return result_list
end

--
--处理闪电
--
function SlotTool.handle_lightning(lgtn_w_list)
    local result_list = {}

    --获得翻倍数
    local rate_num = SlotTool.get_random_result_by_weightlist(lgtn_w_list)
    if not rate_num then
        return
    end
    table.insert(result_list,rate_num)

    return result_list
end

--
--根据随机结果获取额外奖励项
--
function SlotTool.get_ext_prize_item(prize_id)
    
end

--
--保存奖励记录
--
function SlotTool.save_prize_records(gamename, opencard_result)
    local records = {}
    local key = (gamename or "") .. "_prize_records"
    local result,data = redisdao.query_data(".gmmqredis", "get", key)
    if result and data then
        records = json.decode(data) or {}
    end
    
    for _,prize_id in pairs(opencard_result) do
        local id = tostring(prize_id)
        records[id] = (tonumber(records[id]) or 0) + 1
    end
    records.total_count = (tonumber(records.total_count) or 0) + 1
    redisdao.query_data(".gmmqredis", "set", key, json.encode(records))

    ---------------------------------

    --辅助函数1
    local function helper_func(val)
        local cnt = 0
        local tmp = val
        while val >= 10 do
            val = math.floor(val / 10)
            cnt = cnt + 1
        end
        if math.floor(10^cnt) == tmp then
            return true
        end
        return false
    end

    --辅助函数2
    local function func(records)
        local porp_list = {}
        local subprop_list = {}
        local cnt = records.total_count or 0
        if cnt == 0 then
            return
        end

        for k,v in pairs(records) do
            if type(v) ~= "table" and k ~= "total_count" then
                v = tonumber(v) or 0
                porp_list[k] = string.format("%g%%",math.floor(v / cnt * 10000) / 100)
            elseif k == "total_count" then
                porp_list[k] = v
            else
                subprop_list[k] = func(v)
            end
        end
        return porp_list,subprop_list
    end

    --开奖次数每增加10倍，统计一次概率
    if helper_func(records.total_count) then
        local porp_list,subprop_list = func(records)
        filelog.sys_obj("prop_list", records.total_count, porp_list, "=================\n", subprop_list)
    end
    ---------------

    return true
end

--
--创建格式化赔率列表
--
function SlotTool.create_format_odds_list()
    local fmt_odds_list = {}

    for id,odds_list in pairs(Odds_list) do
        for cardstype,odds in pairs(odds_list) do
            if type(odds) == "table" then
                for i = 0,9 do
                    local real_odds = odds[i] or odds[1] or 2
                    local val = tonumber(id) * 10000 + cardstype * 1000 + i * 100 + tonumber(real_odds)
                    table.insert(fmt_odds_list,val)
                end
            else
                for i = 0,9 do
                    local val = tonumber(id) * 10000 + cardstype * 1000 + i * 100 + tonumber(odds)
                    table.insert(fmt_odds_list,val)
                end
            end
        end
    end
    
    return fmt_odds_list
end

--
--保存赔率列表到文件
--
function SlotTool.save_odds_list_to_file()
    local f = io.open("odds_list.lua","w+")
    if not f then
        filelog.print("open file error!")
        return
    end

    f:write("return { \n")
    for id,odds_list in pairs(Odds_list) do
        for cardstype,odds in pairs(odds_list) do
            if type(odds) == "table" then
                for i = 0,9 do
                    local real_odds = odds[i] or odds[1] or 2
                    local val = tonumber(id) * 10000 + cardstype * 1000 + i * 100 + tonumber(real_odds)
                     f:write(tostring(val) .. ",")
                end
            else
                for i = 0,9 do
                    local val = tonumber(id) * 10000 + cardstype * 1000 + i * 100 + tonumber(odds)
                     f:write(tostring(val) .. ",")
                end
            end
        end
    end
    f:write("}")
    f:close()
end


-------------------------------
----------
--外部接口

local CMD = {}

local cs = queue()

function CMD.get_random_dice_result(gamename, total_bet_list, total_bet, avg_bet, is_robot_banker, is_random, banker_round)
    local cnt = 0
    while cnt < 3 do
        local isok,spin_result = skynet.pcall(SlotTool.gen_random_dice_result,gamename,total_bet_list,total_bet, avg_bet,is_robot_banker, is_random, banker_round)
        if isok and SlotTool.check_random_spin_result(spin_result) then
            return spin_result
        end
        cnt = cnt + 1
    end

    return false
end

--
--根据随机结果获取额外奖励
--
function CMD.get_ext_prize_result(prize_id)
    local ext_prize_result = {}

    --根据id获取奖励项
    local item = SlotTool.get_ext_prize_item(prize_id)
    if not item then
        return
    end

    --计算总权值
    local total_w = 0
    local w_list = {}
    for key,val in pairs(item) do
        if type(key) == "string" and string.sub(key,-1) == "w" then
            total_w = total_w + val
            w_list[key] = val
        end
    end
    
    --根据权值表，获取随机结果
    local key = SlotTool.get_random_result_by_weightlist(w_list,total_w)
    if not key or key == "failed_w" then
        return
    end

    --获取额外奖励类型
    local len = string.len(key)
    local extprize_name = string.sub(key,1,len - 2)
    local extprize_type = Extra_prize_type[extprize_name]
    if not extprize_type then
        return
    end

    --获取奖励
    local extprize_list = nil
    
    --返回结果
    ext_prize_result.extprize_type = extprize_type
    ext_prize_result.extprize_list = extprize_list

    return ext_prize_result
end

--
--获取开局奖励
--
function CMD.get_start_prize_result(rids)
    local prize_result_list = {}

    if true then
        return {}
    end

    --获取随机结果
    local function get_random_result(prize_list)
        --计算总权值
        local total_w = 0
        local w_list = {}
        for key,val in pairs(prize_list) do
            if type(key) == "string" and string.sub(key,-1) == "w" then
                total_w = total_w + val
                w_list[key] = val
            end
        end
    
        --根据权值表，获取随机结果
        local key = SlotTool.get_random_result_by_weightlist(w_list,total_w)

        return key
    end

    -------------------

     --开火车奖励表
    local drivetrain_list = SPrize_weight_list[SpecialPrize.SPECIAL_PRIZE_KHC]

    --根据权值表，获取随机结果
    local key = get_random_result(drivetrain_list)
    if not key or key == "failed_w" then
        
    else
        local extprize_list = SlotTool.handle_give_lamp(drivetrain_list.sd_w_list,true)
        local item = {
            extprize_type = Extra_prize_type.drivetrain,
            extprize_list = extprize_list,
        }
        table.insert(prize_result_list,item)
    end

    ------------------

    rids = rids or {}
    
    --低于10人不触发
    local player_num = #rids
    if player_num < 10 then
        return prize_result_list
    end

     --判断是否触发鸿运当头
    local goodluck_list = SPrize_weight_list[SpecialPrize.SPECIAL_PRIZE_HYDT]
    local key = get_random_result(goodluck_list)
    if not key or key == "failed_w" then
        return prize_result_list
    end

    --随机选取10%的人中奖
    local prize_coin_list = {}
    local total_w = SlotTool.calculate_total_weight(goodluck_list.coin_w_list)
    local hit_num = math.floor(player_num * 0.1)
    for i = 1,hit_num do
        local k = base.get_random(1,player_num)
        local rid = rids[k]
        local coin_num = SlotTool.get_random_result_by_weightlist(goodluck_list.coin_w_list,total_w)

        prize_coin_list[rid] = coin_num
        rids[k] = rids[player_num]
        table.remove(rids)
        player_num = #rids
    end
    
    if hit_num > 0 then
        local item = {
            extprize_type = Extra_prize_type.goodluck,
            extprize_list = prize_coin_list,
        }
        table.insert(prize_result_list,item)
    end
 
    return prize_result_list
end

--
--处理开奖
--
function CMD.handle_open_jackpot(gamename, jackpot_id, player_list)
    local award_list = {}

    --获取奖池金额
    local jackpot_money = SlotTool.get_jackpot_from_redis(gamename,jackpot_id)

    --随机开奖
    local total_coin = 0
    local max_level = 6
    for _,item in pairs(player_list) do
        local level = math.floor(item.game_num / 5)
        if level > max_level then
            level = max_level
        end
        local w_list = Jackpot_weight_list[level]
        local award_id = SlotTool.get_random_result_by_weightlist(w_list)
        local award_coin = math.floor(Jackpot_award_list[award_id] * jackpot_money * 0.01)
        local award_item = {
            rid = item.rid,
            logo = item.logo,
            rolename = item.rolename,
            award_money_num = award_coin,
        }
        table.insert(award_list, award_item)
        total_coin = total_coin + award_coin
    end
    
    return award_list,total_coin
end

--
--保存奖励记录
--
function CMD.save_prize_records(gamename, opencard_result)
  return cs(SlotTool.save_prize_records,gamename,opencard_result)
end

--
--处理庄家收益
--
function CMD.handle_banker_profit(ganmename, total_bet_num, player_win_num)
    local banker_win = total_bet_num - player_win_num
    return banker_win
end

--
--更新图标权值表
--
function CMD.update_picture_weight_list(new_w_list)
    if type(new_w_list) ~= "table" then
        return false
    end

    for k,v in pairs(new_w_list) do
        if Weight_list[k] and v >= 0 then
           Weight_list[k] = v
        end
    end
    
    --更新化概率表,总权值
    if next(new_w_list) ~= nil then
        Prob_list,Total_weight_list = SlotTool.update_picture_prob_list()
    end

    return true
end

--
--设置系统输钱上限
--
function CMD.set_system_lose_limit(loselimit_base, loselimit_factor)
    loselimit_base = loselimit_base or 0
    loselimit_factor = loselimit_factor or 0.02
    if loselimit_base < 0 or loselimit_factor < 0 then
        return false
    end
    SystemLoseLimit_Base = loselimit_base
    SystemLoseLimit_Factor = loselimit_factor

    return true
end

--
--获取格式化赔率列表
--
function CMD.get_format_odds_list()
    return SlotTool.create_format_odds_list()
end

--
--处理结算结果
--@total_change 总变化值
--@total_water  总流水值
--@total_bet    玩家总下注
--
function CMD.handle_balance_result(gamename, total_change, total_water, total_bet, comment)
    local tax_rate = SlotTool.get_tax_rate_from_redis(gamename)
    local profit_val = math.floor(total_bet * tax_rate * 100) / 100
    local inventory_val = -total_change

    --更新收益值
    local result1 = SlotTool.update_system_profit(gamename, profit_val, comment)
    if result1 then
        inventory_val = inventory_val - profit_val
    end

    --更新库存值，扣除抽水
    local service_fee_rate = SlotTool.get_service_fee_rate_from_redis(gamename)
    local service_fee_val = math.floor(total_water * service_fee_rate * 100) / 100
    inventory_val = inventory_val - service_fee_val

    return SlotTool.update_system_inventory(gamename, inventory_val, comment)
end

--
--获取抽水率
--
function CMD.get_service_fee_rate(gamename)
    return SlotTool.get_service_fee_rate_from_redis(gamename)
end

-----------
--
--初始化
--
local function init()

    --初始化概率表,总权值
    Prob_list,Total_weight = SlotTool.update_picture_prob_list()
end

-------------------
--
skynet.start(function()
    init()
    skynet.dispatch("lua",function(session, source, cmd, ...)
        local f = CMD[cmd]
        if f then
            skynet.retpack(f(...))
        else
            skynet.retpack()
        end
    end)
end)